#!/lhwl/app/python/python_3.7.3/bin/python3
#_*_coding:utf-8 _*_
#写视频文件备份脚本
#1.查出全部文件
#2.规定一个文件500个文件，将文件列表存入文件
#3.写同步一个文件的方法
#4.写同步一个文件的方法
#5.写同步多个文件的方法
#6.写文件同步完成的标记
#7.写定时检查文件没同步完，又没有这个文件同步进程的发现程序
#8.写发现没同步完文件的处理方法的方法
#    启动该文件同步行为
#    发送同步异常的通知
#9.写全部同步完成的通知机制
#10.写第二次开始同步发现第一次同步还没完成的通知
#11.写微信通知方法
#coding:utf8
import datetime,time,subprocess,os,sys,getopt,hashlib,concurrent.futures,multiprocessing,pymysql
from multiprocessing import Pool
from multiprocessing import cpu_count

sys.setrecursionlimit(10000)

path = '/storage/xxpt/'#这是1.7T所在的目录
project="test"#这次是同步的测试项目地址
rsyncserverIP="218.249.45.162"
rsyncKey="lhwl@"+rsyncserverIP+"::"+project+"/ --password-file=/etc/rsync_root.password"#每个学校的同步地址应该不一样
logDir='/lhwl/log/filesync/'  #日志输出目录
partFileDir=os.path.join(logDir,'partfile')#/lhwl/log/filesync/partfile/#文件列表存放目录
md5File=os.path.join(logDir,"md5List.log")#/lhwl/log/filesync/md5List.log
mysqlHost='172.17.207.73'
database="db_filesync"
port=3306
tablename_filemd5list="table_filemd5list"
tablename_filelist="table_filelist"
user="root"
passwd="passw0rd"
all=0#是否全面同步,如果文件内容经常变化，而文件名不变，就应该全面同步，即all=1,反之，文件内容随文件名一起变，就不需要全面同步。all=0

#sql="create database if not exists db_filesync;use db_filesync;create table if not exists table_filemd5list(filePath VARCHAR(255) NOT NULL,md5 VARCHAR(50),synced VARCHAR(50));"
#sql="create database if not exists db_filesync;use db_filesync;create table if not exists table_filelist(filePath VARCHAR(255) NOT NULL);"

#写一个获取脚本参数的方法
def getopts(argv):
    use="python3 脚本名称 -t video  or python3 脚本名称 --caseType video/mysql"
    result={}
    try:
        opts,args=getopt.getopt(argv,"t:hf:",["help","caseType="])#参数列表；"-t"形式的短参数，带冒号的是要跟参数的，不带冒号的是不用带参数的，使用方法是：-t video;"--caseType"形式的长参数,使用方法是--caseType=video or "--caseType video";opts负责接收前面这种能用元祖类型当元素的参数们，args负责接收不能组成元祖的参数，例如 python a.py -t video --caseType video ni hao ma ,于是“ni hao ma”就被args以元素的形式纳入到列表里了，类似args=["ni","hao","ma"]
        if len(opts)==0:#如果脚本后面没带参数，就输出错误信息，并以错误信号退出
            print(use)
            sys.exit(2)
        else:
            for opt,arg in opts:
                if opt in ("-h","help") or len(opts)==0:#打印帮助信息
                    print(use)
                    sys.exit(0)
                elif opt in ("-t","--caseType"):
                    result["caseType"]=arg
                elif opt in ("-f"):
                    result["-f"]=arg
    except getopt.GetoptError:
        print('Error:'+use)
        sys.exit(2)
    return result#返回结果为字典

def mkdir(dir):  #写一个创建目录的方法
    if os.path.exists(dir) is False:
        os.mkdir(dir)
mkdir(logDir)#创建日志保存目录
mkdir(partFileDir)#创建分片文件保存目录
def getTimeNow(sign):  #写一个获取当前时间的方法
    if sign =='time':
        return datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    elif sign== 'day':
        return datetime.datetime.now().strftime('%Y%m%d')
args=getopts(sys.argv[1:])#sys.argv[1:]是除脚本名字以后的部分
caseType=args["caseType"]#事务类型，为日志输出文件名的定义做准备:video or mysql

logFile=os.path.join(logDir,caseType+'.log'+getTimeNow('day'))#/lhwl/log/filesync/video.log20191228
#写一个记录日志的方法
def log(message):
    with open(logFile,'a+') as f:
        f.write(message+'\n')

#def excuteCommand(com):
#    log('<'+getTimeNow('time')+'>'+'cmd in:'+com)#输出cmd
#    status=0
#    output=''#输出结果
#    try:
#        #ex=subprocess.Popen(com,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True)
#        #ex=subprocess.run(com,shell=True,capture_output=True)#capture_output应用后，不能用err输入到out中去了
#        #ex=subprocess.run(com,sh09ell=True,capture_output=False)#capture_output关闭后，不能用err和out接收数据了
#        #ex=subprocess.run(com,shell=True,capture_output=False,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)#capture_output关闭后，要用pipe接收下次，且err可以输入到out中去了
#        #ex=subprocess.run(com,shell=True,capture_output=False,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,timeout=1)#时间超时后，报错Command 'find / -name adsfsdfs' timed out after 1 seconds，单位秒
#        ex=subprocess.run(com,shell=True,capture_output=False,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,timeout=3600,check=True)#检查结束值开启后，报错Command 'mkdir /a/b/c' returned non-zero exit status 1.
#        #run 不能持续性输出
#        #print(ex.stdout,ex.stderr,ex.returncode)
#        #out,err=ex.communicate()
#        #status=ex.wait()#如果正常结束，状态码为0，如果不正常结束，returncode为127
#        #log('<'+getTimeNow('time')+'>'+'cmd out:'+out.decode()+'####################')#输出cmd结果
#        log('<'+getTimeNow('time')+'>'+'cmd out:'+str(ex.stdout,encoding='utf-8'))
#        output+=str(ex.stdout,encoding='utf-8')
#        log('<'+getTimeNow('time')+'>'+'cmd returnCode:'+str(ex.returncode))
#    except BaseException as error:
#        log('<'+getTimeNow('time')+'>'+'cmd err:'+str(error))
#        output+=str(error)
#        pass
#
#    return output

def excuteCommand(com):
    beginTime=getTimeNow('time')
    log('<'+str(beginTime)+'>'+'cmd in:'+com+'####################')#输出cmd
    status=''
    ex=subprocess.Popen(com,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True)
    try:
        #cwd='c:/'是没用的
        out,err=ex.communicate(timeout=3600)#这个超时很管用
        status=ex.wait()#如果正常结束，状态码为0，如果不正常结束，returncode为127#它的作用完全可以被poll取代，因为wait里接收的timeout=1，根本没用
        log('<'+getTimeNow('time')+'>'+'cmd out:'+out.decode('utf-8')+'####################')#输出cmd结果
        #print('<'+getTimeNow('time')+'>'+'cmd err:'+err.decode('gbk')+'!!!!!!!!!!!!!!!!!!!!')#输出err结果
        status=ex.poll()#等待结束，并返回状态码
        stopTime=getTimeNow('time')
        log('<'+str(stopTime)+'>'+'cmd returnCode:'+str(status)+'                   .')#输出returnCode
        useTime=str(int(stopTime)-int(beginTime))
        log('<'+str(stopTime)+'>'+'cmd useTime:'+useTime+'                   .')#输出useTime
    except BaseException as error:
        #ex.send_signal(1)#如果子进程超时，设置这个，会连同父进程一起退出
        #ex.kill()#如果子进程超时，设置这个，会杀死子进程
        ex.terminate()#如果子进程超时，设置这个，会杀死子进程。推荐这个，因为这个叫停止子进程，上面的叫杀死子进程，不优雅。
        log(error)

    return status

#写一个查找目录文件列表的方法
#listNew=[]#查文件列表是用列表
def getFileList(path,listNew):#path = '/storage/xxpt/'#这是1.7T所在的目录
    #filesize=''
    fileList = os.listdir(path) # 获取path目录下所有文件
    try:
        for filename in fileList:
            pathTmp = os.path.join(path,filename) # 获取path与filename组合后的路径
            if os.path.isdir(pathTmp):   # 判断是否为目录
                getFileList(pathTmp,listNew) # 是目录就继续递归查找#递归使用自身没事，关键是用于收集信息的容器，不要每次都被清空，那样最后啥都剩不下。
            elif os.path.isfile(pathTmp):  # 判断是否为文件
                #    filesize = os.path.getsize(pathTmp) # 如果是文件，则获取相应文件的大小
                #if filesize!='':
                #    dict1[pathTmp]=filesize # 将文件的大小添加到字典
                listNew.append(pathTmp)
    except BaseException as error:
        print(error)
    return listNew#694056

#a=getFileList(path)
#print("共计:"+str(len(a))+"个文件")


#sys.exit(0)
def partFileList(n=500):#规定一个文件500个文件路径，将文件列表存入文件
    partList=[]#定义一个空的分片列表
    global path
    #path = '/storage/xxpt/'#这是1.7T所在的目录
    listNew=[]
    fileList=getFileList(path,listNew)
    print("check file number is:"+str(len(fileList)))
    def a(n):#它需要是个迭代器，需要每次返回一个元素，只不过这个元素我要求是个列表
        for i in range(0,len(fileList),n):#range也是一个迭代器，每次只返回一个值，下一次取值时从上一次结束的时候开始，n表示下一次跨出多少步取值回来。
            yield fileList[i:i+n]#这就是我要求的列表；有了yield，这个方法就是一个迭代器了。
    for i in a(n):#a(n)是一个迭代器，它里面有很多元素，每取走一个下一次再来取时，再回原来return的地方取回来，直到取不到
        partList.append(i)
    return partList#695

def write(content,filePath):#追加内容
    with open(filePath,'a+') as f:
        f.write(content+'\n')

def clearAndWrite(ListOrdirc,filePath):#重写内容
    with open(filePath,"w+") as f:
        for i in ListOrdirc:
            f.write(i+"\n")

def saveList(partFileList): #将文件列表存入文件
    num=1#列表内容存入文件
    for i in partFileList:
        for j in i:
            write(j,os.path.join(partFileDir,str(num)+'.log'))#/lhwl/log/filesync/partfile/1.log
        num+=1

#partFileList=partFileList(500)
#saveList(partFileList)
#sys.exit(1)
#######################################################################到这里已经文件分片完
def readFileToList(path):#写一个读文件成列表的方法
    List=[]
    if os.path.exists(path):
        with open(path) as f :
            for i in f:
                List.append(i.strip())
    return List

def md5(path):#写一个计算文件md5的方法
    #hash1=hashlib.md5()
    #hash1.update(path.encode("utf-8"))
    #return hash1.hexdigest()
    #上面是md5字符串
    #下面是md5文件
    if os.path.exists(path):#如果文件存在就读取它，否则就返回空
        with open(path,'rb')as f:
            data=f.read()
        fileMd5=hashlib.md5(data).hexdigest()
        return fileMd5
    else:
        return 0

#print(md5("/lhwl/app/python/python_3.7.3/bin/python3"))


#写一个查看文件是否打开的方法，如果打开回复false，否则回复true
def getFileStatus(path):
    fileName=os.path.basename(path)
    allFile=[]
    allPid=[_i for _i in os.listdir('/proc') if _i.isdigit()]
    for i in allPid:
        pidPath='/proc/{pid}/fd'.format(pid=i)#这是pid的路径
        try:
            for b in os.listdir(pidPath):#返回pid路径下的文件和文件夹的列表
                object=os.readlink(os.path.join(pidPath,b))
                if os.path.exists(object) and fileName in object:
                    return False
        except BaseException as error:
            pass
    return True
#写一个操作mysql的方法
def mysql (sql,mysqlHost,database,user,passwd,port=3306):
    #sql="create database if not exists db_filesync;use db_filesync;create table if not exists table_filemd5list(filePath VARCHAR(255) NOT NULL,md5 VARCHAR(50),synced VARCHAR(50));"
    conn = pymysql.connect(host=mysqlHost,port=port,user=user,passwd=passwd,db=database)#创建连接
    cursor = conn.cursor()#创建游标
    #执行sql，并返回受影响的行数
    #effect_row = cursor.execute(sql)#执行一条，返回受影响的行数
    if "select" in sql:
        try:
            cursor.execute(sql)
            results = cursor.fetchall()# 获取所有记录列表
            rowList=[]
            for row in results:
                #path = row[0]
                #md5 = row[1]
                #synced=row[2]
                #md5dirc[path]=md5
                rowList.append(row)
            return rowList
        except BaseException as error:
            print ("Error: unable to fetch data")
            print(error)
            conn.close()# 关闭数据库连接
    elif "insert" in sql:
        try:
            cursor.execute(sql)# 执行sql语句
            conn.commit()# 执行sql语句
        except BaseException as error:
            conn.rollback()# 发生错误时回滚
            conn.close()# 关闭数据库连接
            print(error)
    elif "update" in sql:
        try:
            cursor.execute(sql)# 执行SQL语句
            conn.commit()# 提交到数据库执行
        except BaseException as error:
            conn.rollback()# 发生错误时回滚
            conn.close()# 关闭数据库连接
            print(error)
    elif "delete" in sql:
        try:
            cursor.execute(sql)# 执行SQL语句
            conn.commit()# 提交到数据库执行
        except BaseException as error:
            conn.rollback()# 发生错误时回滚
            conn.close()# 关闭数据库连接
            print(error)

#创建数据库
def createDb():
    cmd1="mysql -uroot -ppassw0rd -e 'create database if not exists "+database+" DEFAULT CHARSET utf8;use db_filesync;create table if not exists table_filemd5list(filePath VARCHAR(255) NOT NULL,md5 VARCHAR(50),synced VARCHAR(50));' -P"+str(port)+" -h"+mysqlHost
    cmd2="mysql -uroot -ppassw0rd -e 'create database if not exists "+database+";use db_filesync;create table if not exists table_filelist(filePath VARCHAR(255) NOT NULL);' -P"+str(port)+" -h"+mysqlHost
    status1=excuteCommand(cmd1)
    status2=excuteCommand(cmd2)
    if status1==0 and status2==0:
        pass
    else:
        print('创建数据库失败')
        sys.exit(0)
createDb()

#sql="select * from "+tablename_filemd5list#查
#sql="select * from "+tablename_filemd5list+" where filePath='demo'"#查一个
#sql="insert into "+tablename_filemd5list+" (filePath,md5) values('demo2','demomd6')"#"insert into table_filemd5list (filePath,md5) values ('demo','demomd5')"#插入
#sql="update "+tablename_filemd5list+" set md5='md7' where filepath='demo2'"#更新一个
#sql="delete from "+tablename_filemd5list+" where filepath='demo2'"#删除
#a=mysql(sql,mysqlHost,database,tablename_filemd5list,user,passwd)
#print(a)

#定义md5文件列表存入地址是/lhwl/log/filesync/md5List.log
#md5dirc={}#这是一个字典
def getMd5dirc(md5File="/lhwl/log/filesync/md5List.log"):
    sql="select * from "+tablename_filemd5list
    rowList=mysql(sql,mysqlHost,database,user,passwd,port)
    md5dirc={}
    for row in rowList:
        path = row[0]
        md5 = row[1]
        synced=row[2]
        md5dirc[path]=md5
    return md5dirc
#md5dirc=getMd5dirc(md5File)#得到已有的md5记录
md5dirc=getMd5dirc(md5File)

##########################################################################################
#拿到一个文件列表
#读取文件列表的内容
##多进程给与pool函数
#    #   但是这里有一个删除文件列表的过程，如果进程A写文件，进程B读文件，那么B将读不全。
#    #   所以，多进程不应该发生在同一个列表文件
#    #   梳理如下
#    #对任意一个文件列表执行如下动作A
#        #恒拿取文件列表的第一个数据，直到列表为空
#        #对一条文件记录做处理
#            #md5该条记录
#            #先要判断该记录是否保存在md5列表中
#                #如果存在，在md5记录文件中查找该地址的md5值，对比是否一样；
#                    #如果一样，说明已经同步过了，不需要再同步了
#                        #从文件记录中删除
#                    #如果不一样，说明文件变化了，需要同步B
#                        #执行同步过程
#                        #监听同步结果，如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出
#                        #状态为0，就执行完了这个文件的同步过程
#                        #从文件记录中删除
#                        #将文件记录更新到md5记录中去
#                #如果不存在，B
#                    #执行同步过程
#                    #监听同步结果，如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出
#                    #状态为0，就执行完了这个文件的同步过程
#                    #从文件记录中删除
#                    #将文件记录添加到md5记录中去
#            #当处理完这个文件，检测文件内容是否为空，如果为空，删除，如果不为空，执行A，这一步要检测一下，可能没用上
#读取全部分片文件列表
#对这批文件进行多进程处理
##########################################################################################
#写一个报警方法
def wechat(subject,content):#wechat('报警项目',"报警内容")
    import urllib,urllib.request,json,sys,simplejson,ssl,requests
    ssl._create_default_https_context = ssl._create_unverified_context#当你urllib.urlopen一个 https 的时候会验证一次 SSL 证书 当目标使用的是自签名的证书时就会爆出一个错误

    def gettoken(corpid,corpsecret):#写一个获取token的方法
        gettoken_url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=' + corpid + '&corpsecret=' + corpsecret
        #print(gettoken_url)
        try:
            #token_file = urllib2.urlopen(gettoken_url)
            token_file = urllib.request.urlopen(gettoken_url)
        except BaseException as e:
            print(e)
            print(e.read().decode("utf8"))
            sys.exit(1)
        token_data = token_file.read().decode('utf-8')
        token_json = json.loads(token_data)
        #print(token_json)
        token_json.keys()#拿到key的汇总
        token = token_json['access_token']
        return token
    #gettoken('ww2214ea6644318182','ITOt1F82Oe9o7juxOtZsXloXe27U5wZTDqejPIp3l_s')
    #sys.exit(0)

    def senddata(access_token,subject,content):

        send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + access_token
        send_values = {
            "touser":"guangchao.gao",    #企业号中的用户帐号，在zabbix用户Media中配置，如果配置不正常，将按部门发送。
            "toparty":"2",    #企业号中的部门id。
            "msgtype":"text", #消息类型。
            "agentid":"1000002",    #企业号中的应用id。
            "text":{
                "content":subject + '\n' + content
            },
            "safe":"0"
        }
        send_data = simplejson.dumps(send_values, ensure_ascii=False).encode('utf-8')
        send_request =requests.post(url=send_url,data=json.dumps(send_values))#这样就可以发送了
        #str(send_request.content.decode("utf-8"))
        result=json.loads(send_request.content.decode("utf-8"))
        return result

    #accesstoken=gettoken('ww2214ea6644318182','ITOt1F82Oe9o7juxOtZsXloXe27U5wZTDqejPIp3l_s')
    #senddata(accesstoken,'subject','content')

    corpid = 'ww2214ea6644318182'   #CorpID是企业号的标识
    corpsecret = 'ITOt1F82Oe9o7juxOtZsXloXe27U5wZTDqejPIp3l_s'  #corpsecretSecret是管理组凭证密钥
    accesstoken = gettoken(corpid,corpsecret)
    result=senddata(accesstoken,subject,content)
    return result

def warn(object):#报警内容生成器
    subject="文件同步失败"
    hostname="顺德家具"
    date=getTimeNow("time")
    content=hostname+":"+str(date)+":"+object+"失败"
    print(content)
    result=wechat(subject,content)#微信通知
    log(content)#把通知结果存进日志里
    sys.exit(1)

def checkRsyncResult(path):#检查同步结果
    cmd="rsync -vzrc -R '"+path+"'  "+rsyncKey
    #print(cmd)
    status=excuteCommand(cmd)#执行同步
    if status !=0:#如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出;状态为0，就从文件记录中删除，并将文件记录添加到md5记录中去
        warn(cmd)
    else:#状态为0，就从文件记录中删除，并将文件记录添加到md5记录中去
        #print("完成同步:"+path)
        return 0

def dealOneFileDomd5(fileListPath):#对任意一个文件列表执行如下动作A
    print("doing "+fileListPath)
    fileList=readFileToList(fileListPath)#读取文件列表的内容
    while len(fileList)>0:
        filePath=fileList[0]#对一条文件记录做处理
        fileMd5=md5(filePath)#md5该条记录.如果md5的结果是0，就说明这个文件被删除了，就从文件记录中删除即可，不需要同步了
        if fileMd5==0:
            fileList.remove(filePath)#从列表中删除
            clearAndWrite(fileList,fileListPath)#从文件记录中删除
        else:#md5的结果不是0，说明存在这个文件，可以对比并同步
            if filePath in md5dirc:#先要判断该记录是否保存在md5列表中;
                if fileMd5==md5dirc[filePath]:#如果存在，在md5记录文件中查找该地址的md5值，对比是否一样；
                    fileList.remove(filePath)#如果一样，说明已经同步过了，不需要再同步了,从文件记录中删除
                    clearAndWrite(fileList,fileListPath)#从文件记录中删除
                else:
                    result=checkRsyncResult(filePath)
                    #执行同步过程
                    #监听同步结果，如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出
                    #状态为0，就执行完了这个文件的同步过程
                    if result==0:
                        fileList.remove(filePath)
                        clearAndWrite(fileList,fileListPath)#从文件记录中删除
                        #更新md5记录值
                        sql="update "+tablename_filemd5list+" set md5='"+fileMd5+"' where filepath='"+filePath+"'"#更新一个
                        mysql(sql,mysqlHost,database,user,passwd,port)
            else:#如果不存在，需要同步B
                result=checkRsyncResult(filePath)
                #执行同步过程
                #监听同步结果，如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出
                #状态为0，就执行完了这个文件的同步过程
                #添加md5值
                if result==0:
                    fileList.remove(filePath)
                    clearAndWrite(fileList,fileListPath)#从文件记录中删除
                    sql="insert into "+tablename_filemd5list+" (filePath,md5) values('"+filePath+"','"+fileMd5+"')"#"insert into table_filemd5list (filePath,md5) values ('demo','demomd5')"#插入
                    mysql(sql,mysqlHost,database,user,passwd,port)
                else:
                    print("rsync error")
                    sys.exit(1)
    fileList=readFileToList(fileListPath)
    if len(fileList)!=0:
        dealOneFileDomd5(fileListPath)
    else:
        os.remove(fileListPath)

def dealOneFileNotMd5(fileListPath):#对任意一个文件列表执行如下动作A
    print("doing "+fileListPath)
    fileList=readFileToList(fileListPath)#读取文件列表的内容
    while len(fileList)>0:
        filePath=fileList[0]#对一条文件记录做处理,#否则，就只遍历目录，不md5文件。这适用于全部同步完后，查看哪些文件没有纳入到mysql，就是没有进行同步，用于查错，所以要把这些文件地址记录到一个新表中
        for filePath in fileList:
            if filePath in md5dirc:
                pass
            else:#如果不在已有的列表中，就要md5，并执行同步
                fileMd5=md5(filePath)
                result=checkRsyncResult(filePath)
                #执行同步过程
                #监听同步结果，如果状态为0，就继续，否则就微信报警(host:date:cmd失败)，然后退出
                #状态为0，就执行完了这个文件的同步过程
                if result==0:
                    fileList.remove(filePath)
                    clearAndWrite(fileList,fileListPath)#从文件记录中删除
                    #更新md5记录值
                    sql="insert into "+tablename_filemd5list+" (filePath,md5) values('"+filePath+"','"+fileMd5+"')"#"insert into table_filemd5list (filePath,md5) values ('demo','demomd5')"#插入
                    mysql(sql,mysqlHost,database,user,passwd,port)
                else:
                    print("rsync error")
                    sys.exit(1)
            fileList.remove(filePath)
            clearAndWrite(fileList,fileListPath)#从文件记录中删除
    fileList=readFileToList(fileListPath)
    if len(fileList)!=0:
        dealOneFileNotMd5(fileListPath)
    else:
        os.remove(fileListPath)

#dealOneFile("/lhwl/log/filesync/partfile/test.log")
#dealOneFile("/lhwl/log/filesync/partfile/9.log")
#sys.exit(0)

#第一次同步
listNew=[]
partFilesList=getFileList(partFileDir,listNew)#第二次同步前，要查看上次同步是否完成
print(len(partFilesList))#:718
if partFilesList==0:#这里适用于第一次同步
    saveList(partFileList(n=500))
    listNew=[]
    partFilesList=getFileList(partFileDir,listNew)
    print(len(partFilesList))#:718
p=Pool(cpu_count())#起10个并行进程，别太多，否则会把cpu跑死，还有io，网络等等
if all==1:
    p.map(dealOneFileDomd5,partFilesList)#一个是函数，一个列表，循环列表给函数吃饭，函数消化列表值https://blog.csdn.net/u011808673/article/details/85341977和https://www.cnblogs.com/fugeny/p/9898971.html
else:
    p.map(dealOneFileNotMd5,partFilesList)








